#pragma once

#include<iostream>
#include<vector>
#include<mutex>
#include "Sem.hpp"

namespace RingBufferModule
{
    using namespace SemModule;

    template<class T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap = 10):_capacity(cap), _p_step(0), _c_step(0)
        , _datasem(0), _spacesem(cap), _ring(cap)
        {}
    
        void Equeue(const T& in)
        {
            //先申请信号量，再竞争锁
            //相当于进电影院先买票，再排队进场！！
            _spacesem.P();
            std::lock_guard<std::mutex> lock(_p_lock);
           _ring[_p_step++] = in;
           _p_step %= _capacity; 

            _datasem.V();
        }
        void Pop(T* out)
        {
            //消费者
            //消费者同理
            _datasem.P();
            std::lock_guard<std::mutex> lock(_c_lock);
            *out = _ring[_c_step++];
            _c_step %= _capacity;

            _spacesem.V();
        }
        ~RingBuffer(){}
    private:
        std::vector<T> _ring;  //临界资源
        int _capacity;
        int _p_step;  //生产者位置
        int _c_step;  //消费者位置
        Sem _datasem;  //数据信号量
        Sem _spacesem;  //空间信号量

        std::mutex _p_lock;
        std::mutex _c_lock;
    };
}